﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace IEnumerableExtentions
{
    public static class IEnumerableExtentions
    {
        //rofl
        //private static List<decimal> ConvertTToDecimal<T>(IEnumerable<T> currentEnumerable)
        //{
        //    List<decimal> strangeEnumerable = new List<decimal>();
        //    foreach (var currentItem in currentEnumerable)
        //    {
        //        strangeEnumerable.Add(Convert.ToDecimal(currentItem));
        //    }
        //    return strangeEnumerable;
        //}

        //public static decimal EnumAverage<T>(this IEnumerable<T> currentEnumerable)
        //{
        //    List<decimal> strangeEnumerable = ConvertTToDecimal(currentEnumerable);
        //    return strangeEnumerable.Average();
        //}

        //public static decimal EnumSum<T>(this IEnumerable<T> currentEnumerable)
        //{
        //    List<decimal> strangeEnumerable = ConvertTToDecimal(currentEnumerable);
        //    return strangeEnumerable.Sum();
        //}

        //public static dynamic EnumSum<T>(this IEnumerable<T> currentEnumerable)
        //{
        //    dynamic result = default(T);
        //    foreach (var currentItem in currentEnumerable)
        //    {
        //        result += currentItem;
        //    }
        //    return result;
        //}

        //public static dynamic EnumProduct<T>(this IEnumerable<T> currentEnumerable)
        //{
        //    dynamic result = default(T);
        //    foreach (var currentItem in currentEnumerable)
        //    {
        //        result *= currentItem;
        //    }
        //    return result;
        //}

        //public static dynamic EnumAverage<T>(this IEnumerable<T> currentEnumerable)
        //{
        //    dynamic sum = currentEnumerable.EnumSum();
        //    return sum/currentEnumerable.Count();
        //}

        //public static T EnumMin<T>(this IEnumerable<T> currentEnumerable)
        //{
        //    return currentEnumerable.Min();
        //}

        //public static T EnumMax<T>(this IEnumerable<T> currentEnumerable)
        //{
        //    return currentEnumerable.Max();
        //}

        private static Func<T, T, T> CreateAdd<T>()
        {
            ParameterExpression lhs = Expression.Parameter(typeof(T), "lhs");
            ParameterExpression rhs = Expression.Parameter(typeof(T), "rhs");

            Expression<Func<T, T, T>> addExpr = Expression<Func<T, T, T>>.

            Lambda<Func<T, T, T>>(
                    Expression.Add(lhs, rhs),

                   new ParameterExpression[] { lhs, rhs });


            Func<T, T, T> addMethod = addExpr.Compile();

            return addMethod;
        }

        public static T EnumSum<T>(this IEnumerable<T> vals)
        {

            T total = default(T);

            Func<T, T, T> addMethod = CreateAdd<T>();

            foreach (T val in vals)
            {
                total = addMethod(total, val);
            }

            return total;
        }
    }
}
